import numpy as np
from scipy import integrate
import pandas as pd
from datetime import datetime


class Range:
    def __init__(self):
        aa = 0

    def count(self, kde, x, window_size, total_size):
        count = 0
        result_list = []
        start = datetime.now()

        total_min = x.min()
        total_max = x.max()
        ans = float(0)

        def f_p(*args):
            return np.exp(kde.score_samples(np.array(args).reshape(1, -1)))

        con_time = 1
        for data in x:
            x_min = float(data) - float(window_size)
            if x_min < total_min:
                x_min = total_min
            x_max = float(data) + float(window_size)
            if x_max > total_max:
                x_max = total_max

            if count > con_time:
                ans = integrate.quad(f_p, x_min, x_max, epsabs=10.0, epsrel=0.1)[0] * float(total_size)
                tmp = len(str(int(ans))) - 1
                con_time = pow(10, tmp)
                count = 2
            else:
                count = count + 1

            result_list.append(ans)

        end = datetime.now()
        time_cost = (end - start).total_seconds()
        print("time cost {}".format(time_cost))

        result_list = np.array(result_list)
        return result_list

    def sum(self, kde, x, window_size):
        def f_p(*args):
            return np.exp(kde.score_samples(np.array(args[0]).reshape(1, -1))) * (
                    float(args[0]) / float(args[1]))

        def f_p2(*args):
            return np.exp(kde.score_samples(np.array(args).reshape(1, -1)))

        count = 0
        result_list = []

        start = datetime.now()

        total_min = x.min()
        total_max = x.max()
        x_min = total_min
        x_max = total_min
        ans = float(0)

        for data in x:
            pre_x_min = x_min
            pre_x_max = x_max
            x_min = float(data) - float(window_size)
            if x_min < total_min:
                x_min = total_min
            x_max = float(data) + float(window_size)
            if x_max > total_max:
                x_max = total_max

            current_num_len = len(str(int(data)))
            magnification = pow(10, current_num_len)
            if (abs(pre_x_min - x_min) + abs(pre_x_max - x_max)) > (data / float(10)):
                a = (integrate.quad(f_p, x_min, x_max, epsabs=10.0, epsrel=0.1, args=(magnification,))[
                    0]) * magnification
                b = integrate.quad(f_p2, x_min, x_max, epsabs=10.0, epsrel=0.1)[0]
                if b > 0:
                    ans = (a / b) * (window_size * 2 + 1)

            else:
                x_min = pre_x_min
                x_max = pre_x_max

            result_list.append(ans)
            count = count + 1

        end = datetime.now()
        time_cost = (end - start).total_seconds()
        print("time cost {}".format(time_cost))

        result_list = np.array(result_list)
        return result_list

    def avg(self, kde, x, window_size):
        def f_p(*args):
            return np.exp(kde.score_samples(np.array(args[0]).reshape(1, -1))) * (
                    float(args[0]) / float(args[1]))

        def f_p2(*args):
            return np.exp(kde.score_samples(np.array(args).reshape(1, -1)))

        count = 0
        result_list = []

        start = datetime.now()

        total_min = x.min()
        total_max = x.max()
        x_min = total_min
        x_max = total_min
        ans = float(0)

        for data in x:
            pre_x_min = x_min
            pre_x_max = x_max
            x_min = float(data) - float(window_size)
            if x_min < total_min:
                x_min = total_min
            x_max = float(data) + float(window_size)
            if x_max > total_max:
                x_max = total_max

            current_num_len = len(str(int(data)))
            magnification = pow(10, current_num_len)
            if (abs(pre_x_min - x_min) + abs(pre_x_max - x_max)) > (data / float(10)):
                a = (integrate.quad(f_p, x_min, x_max, epsabs=10.0, epsrel=0.1, args=(magnification,))[
                    0]) * magnification
                b = integrate.quad(f_p2, x_min, x_max, epsabs=10.0, epsrel=0.1)[0]
                if b > 0:
                    ans = a / b

            else:
                x_min = pre_x_min
                x_max = pre_x_max

            result_list.append(ans)
            count = count + 1

        end = datetime.now()
        time_cost = (end - start).total_seconds()
        print("time cost {}".format(time_cost))

        result_list = np.array(result_list)
        return result_list

    def cume_dist(self, kde, x):

        def f_p(*args):
            return np.exp(kde.score_samples(np.array(args).reshape(1, -1)))

        count = 0
        result_list = []

        start = datetime.now()

        total_min = x.min()
        cur_val = total_min
        ans = float(0)

        for data in x:
            pre_val = cur_val
            cur_val = data

            if abs(cur_val - pre_val) > (data / float(10)):
                ans = integrate.quad(f_p, total_min, x, epsabs=10.0, epsrel=0.1)[0]
            else:
                cur_val = pre_val

            result_list.append(ans)
            count = count + 1

        end = datetime.now()
        time_cost = (end - start).total_seconds()
        print("time cost {}".format(time_cost))

        result_list = np.array(result_list)
        return result_list
